import sys

try: __import__('_prepscript_util', globals(), locals(), [], -1)
except ImportError:
    raise SystemError("add the quartet's directory to the PYTHONPATH")

import cldt_datamanip as dm

def path_modify_curdir(path, curdir):
    if path.startswith("."):
        if path[:2] in ( "./", ".\\" ):
            return curdir + path[1:]
    return path

def path_modify_unix2win(path):
    return path.replace("/", "\\")

def path_modify_win2unix(path):
    return path.replace("\\", "/")

__usage = """
Usage: cldt_modfiledesc OPTIONS datafile
Option
  -o output: output file.
  -c cmdfile: reads commands from cmdfile.
  --curdir=...: extends '.' in path of each file.
  --id=newID,filename: changes ID of a named file.
  --renum=curID,newID: changes ID of a file.
  --unix2win: replaces '/' with '\'.
  --win2unix: replaces '\' with '/'.
"""[1:-1]

class _CommandlineParser(object):
    def __getopt(self, args):
        opts, args = getopt.gnu_getopt(args, "ho:c:", 
                [ "curdir=", "unix2win", "win2unix", "renum=", "id=" ])
        return opts, args
        
    def __init__(self, sys_argv):
        import getopt
        
        self.dataFileName = None
        self.outputFileName = None
        self.optionCurDir = None
        self.optionUnix2Win = None
        self.optionWin2Unix = None
        self.tableFilenameToId = dict() # str -> int
        self.tableRenumId = dict() # int -> int

        opts, args = self.__getopt(sys_argv[1:])
        for k, v in opts:
            self.__parseOption(k, v)
        
        for a in args:
            if not self.dataFileName:
                self.dataFileName = a
            else:
                raise SystemError("too many command-line arguments")
        
        if not self.dataFileName:
            raise SystemError("no data file is given")
        
        if self.optionUnix2Win and self.optionWin2Unix:
            raise SystemError("option --unix2win and --win2unix are exclusive")
        
        if not self.optionCurDir and not self.optionUnix2Win and not self.optionWin2Unix and \
                not self.tableFilenameToId and not self.tableRenumId:
            raise SystemError("noting to do")
        
        newIDTbl = dict() # int -> int or str
        for curID, newID in sorted(self.tableRenumId.iteritems()):
            v = newIDTbl.get(newID)
            if v is not None:
                raise SystemError("newID conflict detected: newID=%d, curID or filename=%s, %s" % ( newID, v, curID ))
            newIDTbl[curID] = newID
        for fileName, newID in sorted(self.tableFilenameToId.iteritems()):
            v = newIDTbl.get(newID)
            if v is not None:
                raise SystemError("newID conflict detected: newID=%d, curID or filename=%s, %s" % ( newID, v, fileName ))

    def __parseOption(self, k, v, inCmdFile=False):
        if k == "-h":
            if inCmdFile:
                raise SystemError("option -h is not permitted in cmdfile")
            print __usage
            sys.exit(0)
        elif k == "-o":
            if inCmdFile:
                raise SystemError("option -o is not permitted in cmdfile")
            self.outputFileName = v
        elif k == "-c":
            if inCmdFile:
                raise SystemError("option -c is not permitted in cmdfile")
            cmdFile = v
            with open(cmdFile) as f:
                lines = f.readlines()
            lines = [L.rstrip() for L in lines]
            opts, args = self.__getopt(lines)
            try:
                for k, v in opts:
                    self.__parseOption(k, v, inCmdFile=True)
            except:
                print >> sys.stderr, "error> in reading cmdfile: %s" % cmdFile
                raise
            for a in args:
                if not a.startswith("#"):
                    raise SystemError("invalid option: %s" % args[0])
        elif k == "--curdir":
            self.optionCurDir = v
        elif k == "--unix2win":
            self.optionUnix2Win = True
        elif k == "--win2unix":
            self.optionWin2Unix = True
        elif k == "--renum":
            curID, newID = map(int, v.split(","))
            if curID in self.tableRenumId: raise SystemError("duplicated curID value in option --renum: %d" % curID)
            self.tableRenumId[curID] = newID
        elif k == "--id":
            f0, f1 = v.split(",")
            newID = int(f0)
            fileName = f1
            if fileName in self.tableFilenameToId: raise SystemError("duplicated filename value in option --id: %s" % fileName)
            self.tableFilenameToId[fileName] = newID
        else:
            assert False
            
if __name__ == '__main__':
    import getopt
    
    if len(sys.argv) == 1:
        print __usage
        sys.exit(0)
    
    cmd = _CommandlineParser(sys.argv)
    
    outputFile = open(cmd.outputFileName, "w") if cmd.outputFileName else sys.stdout
    output_write = outputFile.write

    def commentSink(comment):
        output_write("%s\n" % comment)

    if cmd.tableFilenameToId:
        if cmd.tableRenumId:
            def idmod(fileID, pathStr):
                newID = cmd.tableRenumId.get(fileID)
                if newID is not None:
                    ni = cmd.tableFilenameToId.get(pathStr)
                    if ni is not None:
                        raise SystemError("conflict between --renum and --id: --renum=%d,%d, --id=%d,%s" % \
                            ( fileID, newID, ni, pathStr ))
                return newID if newID is not None else fileID
        else:
            def idmod(fileID, pathStr):
                newID = cmd.tableFilenameToId.get(pathStr)
                return newID if newID is not None else fileID
    elif cmd.tableRenumId:
        def idmod(fileID, pathStr):
            newID = cmd.tableRenumId.get(fileID)
            return newID if newID is not None else fileID
    else:
        def idmod(fileID, pathStr): return fileID
                
    if cmd.optionCurDir:
        if cmd.optionUnix2Win:
            def pathmod(pathStr): return path_modify_unix2win(path_modify_curdir(pathStr, cmd.optionCurDir))
        elif cmd.optionWin2Unix:
            def pathmod(pathStr): return path_modify_win2unix(path_modify_curdir(pathStr, cmd.optionCurDir))
        else:
            def pathmod(pathStr): return path_modify_curdir(pathStr, cmd.optionCurDir)
    else:
        if cmd.optionUnix2Win:
            pathmod = path_modify_unix2win
        elif cmd.optionWin2Unix:
            pathmod = path_modify_win2unix
        else:
            def pathmod(pathStr): return pathStr
        
    cur2new = dict()
    fileIDToFilename = dict()
    def fileBegin(): output_write("files:\n")
    def fileSink(fileID, pathStr, length, checksumStr):
        convertedFileID = idmod(fileID, pathStr)
        v = fileIDToFilename.get(convertedFileID)
        if v is not None:
            raise SystemError("two file got the same fileID: fileID=%d, filename=%s, %s" % ( convertedFileID, v, pathStr))
        fileIDToFilename[convertedFileID] = pathStr
        output_write("%d\t%s\t%d\t%s\n" % ( convertedFileID, pathmod(pathStr), length, checksumStr ))
        cur2new[fileID] = convertedFileID
           
    def cloneBegin(): output_write("clone classes:\n")
    def cloneSink(cloneClass):
        output_write("{\n")
        for csi, cloneSubclass in enumerate(cloneClass):
            if csi > 0:
                output_write("--\n")
            for fileID, positions in cloneSubclass:
                output_write("%d\t%s\n" % ( cur2new[fileID], ",".join("%d+%d" % p for p in positions) ))
        output_write("}\n")
    
    dataFile = open(cmd.dataFileName) if cmd.dataFileName != '-' else sys.stdin
    dm.scan_clone_data_file(dataFile, commentSink, fileSink, cloneSink, 
            fileBegin=fileBegin, cloneBegin=cloneBegin)
    if dataFile is not sys.stdin: dataFile.close()
    
    if outputFile is not sys.stdout: outputFile.close()

